package com.gitee.wsl.model.process

import com.gitee.wsl.eventbus.EventDefinition
import com.gitee.wsl.model.ModelHook
import com.gitee.wsl.model.OutgoingContent
import com.gitee.wsl.model.process.call.ProcessClientCall
import com.gitee.wsl.model.process.request.ProcessRequestBuilder
import com.gitee.wsl.model.process.request.RequestPipeline
import com.gitee.wsl.model.process.request.SendPipeline
import kotlinx.coroutines.CoroutineScope
import kotlin.coroutines.CoroutineContext

typealias ProcessModelHook<HookHandler> = ModelHook<ProcessModel,HookHandler>

/**
 * A hook that executes first in request processing.
 */
object SetupRequest : ModelHook<ProcessModel,suspend (ProcessRequestBuilder) -> Unit> {
    override fun install(client: ProcessModel, handler: suspend (ProcessRequestBuilder) -> Unit) {
        client.requestPipeline.intercept(RequestPipeline.Before) {
            handler(context)
        }
    }
}

//typealias SendHookBlock = suspend Send.Sender.(ProcessRequestBuilder) -> ProcessClientCall

/**
 * A hook that can inspect response and initiate additional requests if needed.
 * Useful for handling redirects, retries, authentication, etc.
 */
/* object Send : ModelHook<ProcessModel,suspend Send.Sender.(ProcessRequestBuilder) -> ProcessClientCall> {

     class Sender internal constructor(
        private val httpSendSender: io.ktor.client.plugins.Sender,
        override val coroutineContext: CoroutineContext
    ) : CoroutineScope {
        *//**
         * Continues execution of the request.*//*

         suspend fun proceed(requestBuilder: ProcessRequestBuilder): ProcessClientCall =
            httpSendSender.execute(requestBuilder)
    }

    override fun install(client: ProcessModel, handler: suspend Sender.(HttpRequestBuilder) -> HttpClientCall) {
        client.plugin(HttpSend).intercept { request ->
            handler(Sender(this, client.coroutineContext), request)
        }
    }
}*/

/**
 * A hook that is executed for every request, even if it's not user initiated.
 * For example, if a request results in redirect,
 * [ClientPluginBuilder.onRequest] will be executed only for the original request,
 * but this hook will be executed for both original and redirected requests.
 */
 object SendingRequest : ModelHook<ProcessModel,suspend (request: ProcessRequestBuilder, content: OutgoingContent) -> Unit> {

    override fun install(
        client: ProcessModel,
        handler: suspend (request: ProcessRequestBuilder, content: OutgoingContent) -> Unit
    ) {
        client.sendPipeline.intercept(SendPipeline.State) {
            handler(context, subject as OutgoingContent)
        }
    }
}

/**
 * A shortcut hook for [HttpClient.monitor] subscription.
 */
class MonitoringEvent<Param : Any, Event : EventDefinition<Param>>(private val event: Event) : ModelHook<ProcessModel,(Param) -> Unit> {

    override fun install(client: ProcessModel, handler: (Param) -> Unit) {
        client.monitor.subscribe(event) {
            handler(it)
        }
    }
}
